package protocol;

import java.util.Arrays;

import utils.Conversions;

/**
 * Represents the packet header.
 * Included in every packet.
 * 		12 bytes in length
 * 
 */
public class CtfHeader {
	
	public static final int LENGTH = 12;	
	
	/* Instance Variables */
	/**
	 *  0	Server
	 *  0	Unassigned Client
	 *  +	Client idInGame 	(once assigned)
	 */
	int sender;
	/**	
	 *  -	updates from server
	 *  0	map transmission
	 *  +	client commands		(response type == request type)
	 *  @see MsgTypes
	 */
	int msgType;
	/**
	 * Notion of event-based clock.
	 *  0	game not yet started
	 *  1	Game Update Start
	 *  +	Each update++
	 */
	int updateState;
	/**
	 *  0	No message
	 *  +	Length of body message
	 */
	int bodyLength;

	
	/* Constructor: parameters passed in from received response string */
	public CtfHeader( int sender, int msgType, int updateState, 
					int bodyLength ) 
	{
		this.sender = sender;
		this.msgType = msgType;
		this.updateState = updateState;
		this.bodyLength = bodyLength;
		
	}
	
	/* Constructor: from received network byte array */
	public CtfHeader( byte[] packet ) {
		// grab each byte array representing an integer in network byte order
		byte[] senderInBytes = 		  Arrays.copyOfRange(packet, 0, 2);
		byte[] msgTypeInBytes = 	  Arrays.copyOfRange(packet, 2, 4);
		byte[] updateStateInBytes = 	  Arrays.copyOfRange(packet, 4, 8);
		byte[] bodyLengthInBytes =	  Arrays.copyOfRange(packet, 8, 12);

		
		// convert each integer to host byte order
		this.sender = 		Conversions.bytesToInt( senderInBytes );
		this.msgType = 		Conversions.bytesToInt( msgTypeInBytes );
		this.updateState = 	Conversions.bytesToInt4( updateStateInBytes );
		this.bodyLength = 	Conversions.bytesToInt4( bodyLengthInBytes );
	}
	
	/* Constructor: for client purposes */
	public CtfHeader( int sender, int msgType, int updateState ) 
	{
		this.sender = sender;
		this.msgType = msgType;
		this.updateState = updateState;
		this.bodyLength = 0;			// no body
	}
	
	/* Constructor: from delimited string, for testing purposes */
	public CtfHeader( String packet, String delimiter ) {
		String[] fields = packet.split(delimiter);
		this.sender 	= Integer.parseInt( fields[0] );
		this.msgType 	= Integer.parseInt( fields[1] );
		this.updateState 	= Integer.parseInt( fields[2] );
		this.bodyLength = Integer.parseInt( fields[3] );
	}
	
	/* Converts a CtfHeader to a byte array in network byte order */
	public byte[] toNetworkByteArray() {
		// convert each field to a 2-byte array in network byte order
		byte[] headerInBytes = new byte[ LENGTH ];
		byte[] senderInBytes = 		Conversions.intToBytes( this.sender );
		byte[] msgTypeInBytes =	 	Conversions.intToBytes( this.msgType );
		byte[] updateStateInBytes = 	Conversions.int4ToBytes( this.updateState );
		byte[] bodyLengthInBytes = 	Conversions.int4ToBytes( this.bodyLength );

		
		// concatenate the arrays into the header in byte form
		System.arraycopy( senderInBytes, 		0, headerInBytes, 0, 2);
		System.arraycopy( msgTypeInBytes, 		0, headerInBytes, 2, 2);
		System.arraycopy( updateStateInBytes, 	0, headerInBytes, 4, 4);
		System.arraycopy( bodyLengthInBytes, 	0, headerInBytes, 8, 4);
		
		return headerInBytes;
	}
	
	/* Accessors */
	public int getSender() 				{ return sender; }
	public int getMsgType() 			{ return msgType; }
	public int getUpdateState() 		{ return updateState; }
	public int getBodyLength() 			{ return bodyLength; }
	
	/* String representation for transmission purposes*/
	public String toString() {

		return "" + this.sender + "," + this.msgType + "," + this.updateState + 
		 		"," + this.bodyLength;
	}
}
